package com.panghl.controller;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.*;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.panghl.config.AlipayClientConfig;
import com.panghl.entity.OrderInfo;
import com.panghl.service.AliPayService;
import com.panghl.service.OrderInfoService;
import com.panghl.vo.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.Map;

/**
 * @Author:Panghl
 * @Description:
 * @Date: Created in 7:56 2022/5/7
 * @Modified By:
 */
@RestController
@RequestMapping("/api/ali-pay")
@Api(tags = "支付宝支付")
@Slf4j
public class AliPayController {

    @Autowired
    private AliPayService aliPayService;

    @Autowired
    private AlipayClientConfig alipayClientConfig;

    @Autowired
    private OrderInfoService orderInfoService;


    @ApiOperation("统一下单并支付页面接口的调用")
    @PostMapping("/trade/page/pay/{productId}")
    public R tradePagePay(@PathVariable("productId") Long productId) throws AlipayApiException {
        log.info("统一收单下单并支付页面接口的调用");
        // 支付宝开放平台接受 request 请求对象后
        // 会为开发者生成一个html形式的form表单  ，包含自动提交的脚本
        String formStr = aliPayService.tradeCreate(productId);
        // 将form表单字符串返回前端程序，之后前段将会调用自动提交脚本，进行表单的提交；
        // 此时，表单会自动提交到action属性所指向的支付宝开放平台中，从而为用户展示一个支付页面。
        return R.ok().data("formStr",formStr);
    }

    @ApiOperation("支付通知")
    @PostMapping("/trade/notify")
    public String tradeNotify(@RequestParam Map<String,String> params) throws AlipayApiException {

        log.info("支付通知正在执行");
        log.info("通知参数 ==> {}",params);
        String result = "failure";

        // 异步通知验签
        boolean signVerified = AlipaySignature.rsaCheckV1(params, alipayClientConfig.getAlipayPublicKey(),
                AlipayConstants.CHARSET_UTF8, AlipayConstants.SIGN_TYPE_RSA2);//调用SDK验证签名

        if (!signVerified){
            // TODO 验签失败则记录异常日志，并在response中返回failure.
            log.error("支付成功异步通知验签失败!");
            return result;
        }
        log.info("支付成功异步通知验签成功!");

        // TODO 验签成功后，按照支付结果异步通知中的描述，对支付结果中的业务内容进行二次校验，

//        1. 商户需要验证该通知数据中的 out_trade_no 是否为商户系统中创建的订单号；
        String out_trade_no = params.get("out_trade_no");
        OrderInfo orderInfo = orderInfoService.getOrderByOrderNo(out_trade_no);
        if (orderInfo == null){
            log.error("订单不存在");
            return result;
        }

//        2. 判断 total_amount 是否确实为该订单的实际金额（即商户订单创建时的金额）；
        String total_amount = params.get("total_amount");
        int totalAmountInt = new BigDecimal(total_amount).multiply(BigDecimal.valueOf(100)).intValue();
        if (totalAmountInt != orderInfo.getTotalFee().intValue()) {
            log.error("订单的实际金额校验失败");
            return result;
        }

//        3. 校验通知中的 seller_id（或者 seller_email) 是否为 out_trade_no 这笔单据的对应的操作方（有的时候，一个商户可能有多个 seller_id/seller_email）；
        String sellerId = params.get("seller_id");
        String sellerIdProperty = alipayClientConfig.getSellerId();

        if (!sellerId.equals(sellerIdProperty)){
            log.error("商家pid校验失败");
            return result;
        }
//        4. 验证 app_id 是否为该商户本身。
        String app_id = params.get("app_id");
        String appIdProperty = alipayClientConfig.getAppId();
        if (!app_id.equals(appIdProperty)){
            log.error("appid校验失败");
            return result;
        }

        // 在支付宝的业务通知中，只有交易通知状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时，支付宝才会认定为买家付款成功
        String trade_status = params.get("trade_status");
        if (!"TRADE_SUCCESS".equals(trade_status)){
            log.error("支付未成功");
            return result;
        }

        //  校验成功后在response中返回success并继续商户自身业务处理，校验失败返回failure
        // todo 处理业务 修改订单状态  记录支付日志
        aliPayService.processOrder(params);

        // 向支付宝返回成功的结果
        result = "success";
        return result;
    }


    @ApiOperation("用户取消订单")
    @PostMapping("/trade/close/{orderNo}")
    public R cancel(@PathVariable String orderNo) throws AlipayApiException {
        log.info("取消订单");
        aliPayService.cancelOrder(orderNo);
        return R.ok().setMessage("订单已取消");
    }

    @ApiOperation("查询订单")
    @GetMapping("/trade/query/{orderNo}")
    public R queryOrder(@PathVariable String orderNo) throws IOException, AlipayApiException {
        log.info("查询订单");
        String result = aliPayService.queryOrder(orderNo);
        return R.ok().setMessage("查询成功").data("result",result);
    }

    /**
     * 申请退款
     * @param orderNo
     * @param reason
     * @return
     */
    @ApiOperation("申请退款")
    @PostMapping("/trade/refund/{orderNo}/{reason}")
    public R refunds(@PathVariable String orderNo, @PathVariable String reason){

        log.info("申请退款");
        aliPayService.refund(orderNo, reason);
        return R.ok();
    }

    /**
     * 查询退款
     * @param orderNo
     * @return
     * @throws Exception
     */
    @ApiOperation("查询退款：测试用")
    @GetMapping("/trade/fastpay/refund/{orderNo}")
    public R queryRefund(@PathVariable String orderNo) throws Exception {

        log.info("查询退款");

        String result = aliPayService.queryRefund(orderNo);
        return R.ok().setMessage("查询成功").data("result", result);
    }

    /**
     * 根据账单类型和日期获取账单url地址
     *
     * @param billDate
     * @param type
     * @return
     */
    @ApiOperation("获取账单url")
    @GetMapping("/bill/downloadurl/query/{billDate}/{type}")
    public R queryTradeBill(
            @PathVariable String billDate,
            @PathVariable String type)  {
        log.info("获取账单url");
        String downloadUrl = aliPayService.queryBill(billDate, type);
        return R.ok().setMessage("获取账单url成功").data("downloadUrl", downloadUrl);
    }

}
